<?php
/**
 * “虚拟机”类
 * 
 * 定义了一些基础的方法
 *
 * @package if
 * @subpackage vm
 * @since 1.0
 */
class IVM {
	private static $instance;
	private $classPaths = array();
	private $classIndexes = array();
	private $classRules = array();
	
	/**
	 * 构造器
	 *
	 * @since 1.0
	 */
	private function __construct() {
		
	}
	
	/**
	 * 取得当前类的单例
	 *
	 * @return IVM
	 * @since 1.0
	 */
	static function singleton() {
		if (!self::$instance) {
			self::$instance = new self();
		}
		return self::$instance;
	}
	
	function addClassPath($classPath) {
		$args = func_get_args();
		foreach ($args as $arg) {
			if (is_array($arg)) {
				$this->classPaths = array_merge($this->classPaths, $arg);
			}
			else {
				$this->classPaths[] = $arg;
			}
		}
		$this->classPaths = array_unique($this->classPaths);
	}
	
	function findClass($class) {	
		$lowerClass = strtolower($class);
		
		//从索引中找
		if (isset($this->classIndexes[$lowerClass])) {
			$filename = $this->classIndexes[$lowerClass];
			if (if_is_absolute_path($filename)) {
				return $filename;
			}
			return IF_FW_DIR . "/" . $this->classIndexes[$lowerClass];
		}
		
		//从class_path中找
		$class = str_replace(".", DIRECTORY_SEPARATOR, $class);
		foreach ($this->classPaths as $classPath) {
			$file = $classPath . "/" . $class . ".php";
			if (is_file($file)) {
				if (!if_is_absolute_path($file)) {
					$file = realpath($file);
				}
				return $file;
			}
		}
		
		//快捷查找
		if (!empty($this->classRules)) {
			foreach ($this->classRules as $regex => $classRule) {
				extract($classRule);
				if (@preg_match("/^" . $regex . "$/i", $class, $match)) {
					foreach ($find as $tryClass) {
						$tryClass = if_name_to_c(preg_replace("/\\$(\d+)/e", "isset(\$match[\\1])?\$match[\\1]:null", $tryClass));
						$found = $this->importClass($tryClass, false, $dir);
						if ($found) {
							return array_shift($found);
						}
					}
				}
			}
		}
		
		return null;
	}
	
	function importClass($class, $check = true, $basedir = null) {
		$files = array();
		
		//如果有多个用逗号隔开的类
		if (strstr($class, ",")) {
			$classes = explode(",", $class);
			foreach ($classes as $class) {
				$class = trim($class);
				$_files = $this->importClass($class, $check, $basedir);
				if (is_array($_files)) {
					$files = array_merge($files, $_files);
				}
			}
			return $files;
		}
		
		//是否已经存在
		$realClass = if_class_name($class);
		if ($check && class_exists($realClass, false)) {
			return array();
		}
		
		//从类索引中查找
		$lowerClass = strtolower($class);
		if (isset($this->classIndexes[$lowerClass])) {
			$filename = $this->classIndexes[$lowerClass];
			if (!if_is_absolute_path($filename)) {
				$filename = IF_FW_DIR . "/" . $filename;
			}
			$this->loadFile($filename, true);
			return array($realClass => $filename);
		}
		
		//从class-path中查找
		$findPaths = array();
		if (is_null($basedir)) {
			$findPaths = $this->classPaths;
		}
		else {
			$findPaths = array($basedir);
		}
		foreach ($findPaths as $classPath) {
			$file = $classPath . DIRECTORY_SEPARATOR . str_replace(".", DIRECTORY_SEPARATOR, $class) . ".php";
			if (is_file($file)) {
				//添加规则
				if (preg_match("/app\/controllers/i", $file)) {
					$this->addClassRule("(.+)controller", dirname($file), array("$1"));
				}
				
				//返回
				$this->addClassPath(dirname($file));
				$this->loadFile($file, true);
				$files[$realClass] = $file;
			}
			else if (strstr($file, "?") || strstr($file, "*")) {
				$array = glob($file);
				foreach ($array as $path) {
					if (is_file($path)) {
						$this->addClassPath(dirname($path));
						$this->loadFile($path, true);
					}
				}
			}
		}
		return $files;
	}

	
	function classPackage($class) {
		if ($class == "" || !strstr($class, ".")) {
			return null;
		}
		$pieces = explode(".", $class);
		array_pop($pieces);
		return implode(".", $pieces);
	}
	
	/**
	 * 判断一个类名称（包括包名）是否可用
	 *
	 * @param string $className 类名称（可以含包名，如 a.b.c.ExampleClass）
	 * @return boolean
	 * @since 1.0
	 */
	function isValidClassName($className) {
		if (preg_match("/^([_a-z]\\w*\\.)*([_a-z]\\w*)$/i", $className)) {
			return true;
		}
		return false;
	}
	

	
	function classPaths() {
		return $this->classPaths;
	}
	
	function addClassIndexes($indexes, $toLower = false) {
		if (is_array($indexes)) {
			if ($toLower) {
				$_indexes = array();
				foreach ($indexes as $class => $file) {
					$_indexes[strtolower($class)] = $file;
				}
				$indexes = $_indexes;
			}
			if (empty($this->classIndexes)) {
				$this->classIndexes = $indexes;
			}
			else {
				$this->classIndexes = array_merge($this->classIndexes, $indexes);
			}
		}
	}
	
	function classIndexes() {
		return $this->classIndexes;
	}
	
	function loadFile($filename, $once = false) {
		if (!is_file($filename)) {
			return;
		}
		if ($once) {
			return require_once($filename);
		}
		else {
			return require($filename);
		}
	}
	
	/**
	 * Enter description here...
	 * 
	 * classRule: "(.+)Controller" => array("dir" => "/opt/app/controllers", "find" => array("$1")
	 *
	 * @param unknown_type $regex
	 * @param unknown_type $rule
	 * @since 1.0
	 */
	function addClassRule($regex, $dir, array $find) {
		$this->classRules[$regex] = array("dir" => $dir, "find" => $find);
	}
}

?>